;> Replace
;Lexical translation of find string (in stracc) into trans buffer
FINDTR MOV FLAGR,#0
 ADD R8,ARGP,#TRANS ;buffer for translated string
 ADD R7,ARGP,#STRACC ;input buffer
 MOV R6,#0 ;offset
 ADD R5,ARGP,#FIELDT ;field index
 MOV R4,#0 ;mmx
 STMFD SP!,{R14}
FINDPT BIC FLAGR,FLAGR,#MULFFLAG+METAFLAG
 LDRB R0,[R7],#1
 TEQ R0,#128+5
 ORREQ FLAGR,FLAGR,#REPLFLAG
 TEQNE R0,#CR
 BNE FP1
 MOV R0,#TERMSYM
 STRB R0,[R8],#1
 SUB R5,R5,#FIELDT
 SUB R5,R5,ARGP
 MOV R5,R5,LSR #1
 LDMFD SP!,{R14}
 STR R8,[ARGP,#REPADR] ;save proposed start of replace part
 STRB R5,[ARGP,#MAXFLD] ;maximum number of fields
 TST FLAGR,#REPLFLAG
 MOVEQ PC,R14
;Lexical translation of replace part (R7) into rest of trans buffer (r8)
REPLTR STMFD SP!,{R14}
 LDRB R5,[ARGP,#MAXFLD]
REPLPT LDRB R0,[R7],#1
 TEQ R0,#CR
 MOVEQ R0,#TERMSYM
 STREQB R0,[R8],#1
 LDMEQFD SP!,{PC}
 TEQ R0,#128+2
 MOVEQ R0,#FOUNDSYM
 STREQB R0,[R8],#1
 BEQ REPLPT
 TEQ R0,#128+16+5
 BNE REPANS
 BL NEXTCH
 STRB R0,[R8],#1
 B REPLPT
REPANS TEQ R0,#128+1
 BNE REPNFL
 MOV R0,#FIELDSYM
 BL GENNEXT
 SUBS R0,R0,#"0"
 BCC ERRFLD
 CMP R0,R5
 BCS ERRFLD
 STRB R0,[R8],#1
 B REPLPT
REPNFL BL CHARACTER
 CMP R0,#&80
 MOVCS R1,#ESCSYM
 STRCSB R1,[R8],#1
 STRB R0,[R8],#1
 B REPLPT
FP1 TEQ R0,#128+16+6
 EOREQ FLAGR,FLAGR,#SENSFLAG
 BEQ FINDPT
 TEQ R0,#128+3
 ORREQ FLAGR,FLAGR,#MULFFLAG+METAFLAG
 MOVEQ R0,#MAXSYM
 BLEQ GENNEXT
 TEQ R0,#128+4
 ORREQ FLAGR,FLAGR,#MULFFLAG+METAFLAG
 MOVEQ R0,#MULTSYM
 BLEQ GENNEXT
 TEQ R0,#128+6
 MOVEQ R0,#NOTSYM
 BLEQ GENMETA
 TEQ R0,#128+16+0
 BNE FPSIMP
 ORR FLAGR,FLAGR,#METAFLAG
 STMFD SP!,{FLAGR}
 ORR FLAGR,FLAGR,#SENSFLAG ;case sensitive
 MOV R0,#SETSYM
 BL GENNEXT
 STMFD SP!,{R8}
 ADD R8,R8,#1
FPSET1 BL SIMPLE
 BL NEXTCH
 TEQ R0,#128+16+1
 BNE FPSET1
 LDMFD SP!,{R0}
 SUB R1,R8,R0
 STRB R1,[R0] ;store end of set offset
 LDMFD SP!,{FLAGR}
 B FPDONE
FPSIMP BL SIMPLE
FPDONE TST FLAGR,#METAFLAG
 BEQ FPFOFF
 SUB R14,R5,ARGP
 CMP R14,#FIELDT+20
 BCS FINDPT ;too many fields so block out this section
 STRB R6,[R5],#1 ;put offset into first byte of fields
 TST FLAGR,#MULFFLAG
 MVNNE R6,#0 ;set offset to -1 (i.e. 0 after the inc at fpfoff)
 ADDNE R4,R4,#1
 ORRNE R4,R4,#&80 ;set top bit
 STRB R4,[R5],#1 ;Put either mmx or inc mmx OR &80 into second byte of fields
 BIC R4,R4,#&80 ;clear top bit
FPFOFF ADD R6,R6,#1 ;offset
 B FINDPT
SIMPLE STMFD SP!,{R14}
SIMP0 TEQ R0,#128+6
 MOVEQ R0,#NOTSYM
 BLEQ GENMETA
 TEQ R0,#128+16+5
 BNE SIMP1
 BL NEXTCH
 MOV R1,#ESCSYM
 STRB R1,[R8],#1
 B SIMP10
SIMPMT ORR FLAGR,FLAGR,#METAFLAG ;if a meta char set the flag
SIMP10 STRB R0,[R8],#1 ;case sensitive for escape
 LDMFD SP!,{PC}
SIMP1 TEQ R0,#128+7
 MOVEQ R0,#WILDSYM
 BEQ SIMPMT
 TEQ R0,#128+8
 MOVEQ R0,#ALPHASYM
 BEQ SIMPMT
 TEQ R0,#128+9
 MOVEQ R0,#DIGSYM
 BEQ SIMPMT
 BL CHARACTER
 LDRB R1,[R7]
 TEQ R1,#128+16+2
 BNE SIMP2
 MOV R1,#SUBRSYM
 STRB R1,[R8],#1 ;subrange
 BL GENMETA ;start character. Skip the "to"
 BL NEXTCH ;end character read
 BL CHARACTER
 B SIMP10
SIMP2 CMP R0,#&80
 MOVCS R1,#ESCSYM
 STRCSB R1,[R8],#1
 BCS SIMP10
 TST FLAGR,#SENSFLAG
 BNE SIMP10 ;case sensitive currently
 CMP R0,#"A"
 BCC SIMP10
 CMP R0,#"z"
 BHI SIMP10
 CMP R0,#"Z"
 BLS SIMP3
 CMP R0,#"a"
 BCC SIMP10
SIMP3 MOV R1,#NSENSYM
 STRB R1,[R8],#1
 ORR R0,R0,#&20
 B SIMP10
;complex character recognition $, |, |!, |?
CHARACTER TEQ R0,#128+0
 MOVEQ R0,#TERM
 MOVEQ PC,R14
 TEQ R0,#128+16+4
 BEQ CHAR1
 TEQ R0,#128+16+3
 MOVNE PC,R14
 LDRB R0,[R7],#1
 TEQ R0,#CR
 BEQ ERRCR
 TEQ R0,#"?"
 MOVEQ R0,#&7F
 MOVEQ PC,R14
 CMP R0,#"@"
 MOVCC PC,R14
 AND R0,R0,#&DF
 SUB R0,R0,#"@"
 MOV PC,R14
CHAR1 STMFD SP!,{R14}
 BL NEXTCH
 BL CHARACTER
 ORR R0,R0,#&80
 LDMFD SP!,{PC}
GENMETA ORR FLAGR,FLAGR,#METAFLAG
;stick R0 into output and get new input into R0. Fault if at end
GENNEXT STRB R0,[R8],#1
NEXTCH LDRB R0,[R7],#1
 TEQ R0,#CR
 MOVNE PC,R14
ERRCR BL MSG
 = "Syntax incorrect",0
 ALIGN
ERRFLD BL MSG
 = "Incorrect or too large field number",0
 ALIGN
SRCHXT ADDS R0,R0,#0 ;clear carry
 LDMFD SP!,{PC}
;Search routine
;Enter with R5 at search start R6 at search end. Search string in Trans
;Exit with CC implies found, CS not found
;     R4 at match start, R5 at match end
SEARCH STMFD SP!,{R14}
 ADD R3,ARGP,#MSTACK ;multiple occurence stack
;the multiple occurence stack remembers 3 words of info
;1: address of item in trans when multsym occured
;2: text address of match start
;3: text address of match end
SRCHON CMP R5,R6
 LDMCSFD SP!,{PC} ;search fail: no text to look in!
 LDRB R7,[ARGP,#ESCFLG]
 CMP R7,#&80
 BCS ESCAPE
 ADD R7,ARGP,#TRANS
 MOV R4,R5 ;remember start position
SRCHCT LDRB R0,[R7],#1 ;match character
 TEQ R0,#TERMSYM
 BEQ SRCHXT ;succeed!!!!!
 TEQ R0,#MULTSYM
 BEQ SRCHMI
 LDRB R2,[R5],#1 ;get store item
 TEQ R0,#MAXSYM
 BEQ SRCHMAX
 BL COMP ;try a match
 BEQ SRCHCT ;o.k., try next
;Now we have failed to recognise the object. If in a multiple match move on
;Otherwise advance match start (r4 into r5) and search again
SRCHIN SUB R14,R3,ARGP
 TEQ R14,#MSTACK
 ADDEQ R5,R4,#1
 BEQ SRCHON
;let most recent multiple match accept another occurence of the find object
 LDR R5,[R3,#-4] ;match end
 LDR R7,[R3,#-12] ;position
 LDRB R0,[R7],#1
 LDRB R2,[R5],#1
 BL COMP
 BNE SRCHBK
 STR R5,[R3,#-4] ;update end
 CMP R5,R6
 LDMCSFD SP!,{PC} ;search fail: no text to look in!
 B SRCHCT ;continue
;no more matches possible for this find multiple, so backtrack
SRCHBK SUB R3,R3,#12
 B SRCHIN
;initialise stack for a multiple object
SRCHMI STMIA R3!,{R7} ;position in trans buffer
 STMIA R3!,{R5} ;match start
 STMIA R3!,{R5} ;match end
 LDRB R0,[R7],#1
 BL COMP ;bypass the object which we're finding multiples of
 B SRCHCT
SRCHMAX STMFD SP!,{R7}
 LDRB R0,[R7],#1
 BL COMP
 ADDNE SP,SP,#4
 BNE SRCHIN
 SUB R2,R7,#1
 STMIA R3!,{R2} ;position in trans buffer
 SUB R2,R5,#1
 STMIA R3!,{R2} ;match start
SRCHMAX1 LDRB R2,[R5],#1
 LDMFD SP,{R7}
 LDRB R0,[R7],#1
 BL COMP
 BEQ SRCHMAX1
SRCHMAX2 SUB R5,R5,#1
 STMIA R3!,{R5} ;match end
 ADD SP,SP,#4
 B SRCHCT
;compare an item (in R0..[r7]) with item from memory (in r2) upto R6 limit
;Exit with EQ status if match, NE otherwise
COMP CMP R5,R6
 BHI COMPFL ;search fail: no text to look in!
 CMP R0,#NSENSYM
 BCC CPDEFT
 BEQ CPNSEN
 CMP R0,#NOTSYM
 BCC CPWILD ;wildsym=notsym-1
 BEQ CPNOT
 CMP R0,#DIGSYM
 BCC CPALPHA ;alphasym=digsym-1
 BEQ CPDIG
 CMP R0,#SETSYM
 BCC CPSUBR ;subrsym=setsym-1
 BEQ CPSET
 CMP R0,#ESCSYM
 LDREQB R0,[R7],#1 ;if escsym then get next character
CPDEFT CMP R2,R0 ;easy test. Exact match (default) or ESCSYM
 MOV PC,R14
CPNOT LDRB R0,[R7],#1 ;next char after not
 STMFD SP!,{R14}
 BL COMP
 LDMFD SP!,{R14}
 BEQ COMPFL
CPWILD ;a wild match always succeeds!
COMPSD TEQ R2,R2 ;succeeded
 MOV PC,R14
CPNSEN LDRB R0,[R7],#1 ;case insensitive match
 ORR R2,R2,#&20
 CMP R2,R0
 MOV PC,R14
CPALPHA CMP R2,#"_"
 MOVEQ PC,R14
 ORR R2,R2,#&20 ;take if A-Z
 CMP R2,#"a"
 BCC CPDIG
 CMP R2,#"z"
 BLS COMPSD ;take if a-z
CPBUTT ;butt sym always fails so that it elongates wild match
COMPFL MOVS R2,#1 ;fail not equal
 MOV PC,R14
CPDIG CMP R2,#"9"
 BHI COMPFL
 CMP R2,#"0"
 BCS COMPSD
 B COMPFL
CPSUBR LDRB R0,[R7],#1 ;subrange: first character
 LDRB R1,[R7],#1 ;subrange second character
 CMP R2,R0
 BCC COMPFL ;fail if lower than first
 CMP R2,R1
 BHI COMPFL ;fail if higher than second
 B COMPSD
CPSET LDRB R0,[R7],#1 ;set: offset to end
 ADD R0,R7,R0
 SUB R0,R0,#1
 STMFD SP!,{R14,R0}
CPSET1 LDRB R0,[R7],#1
 BL COMP
 LDMEQFD SP!,{PC,R7} ;succeed: replace R7 and return
 LDR R0,[SP]
 CMP R7,R0
 BCC CPSET1
 MOVS R0,#1 ;ne
 LDMFD SP!,{PC,R0}
;replace routine
;enter with r4,r5 at match start, match end; replace string in [repadr]
;exit with r5,r6 as entry. Adjust address in R8 to compensate for replace
REPLACE STMFD SP!,{R4,R5,R6,R14}
 BL GPFWD ;move gap end to start of match
 MOV R0,#1
 STRB R0,[AP,#MODIFY]
 MOV UPDATE,#FULLSCREEN
 LDMFD SP!,{R4,R5,R6}
 LDR R7,[ARGP,#REPADR]
 LDR R3,[AP,#GS]
 MOV R1,R3 ;remember old gs
REPL1 CMP R3,R4
 BCS REPLER
 LDRB R0,[R7],#1
 CMP R0,#TERMSYM
 BEQ REPLEX
 CMP R0,#FIELDSYM
 BEQ REPLF1
 CMP R0,#FOUNDSYM
 BEQ REPLAM
 CMP R0,#ESCSYM
 BEQ REPLES
 STRB R0,[R3],#1
 B REPL1
REPLEX STR R3,[AP,#GS]
 STR R5,[AP,#GE]
 CMP R5,R8 ;if new GE <= then remembered address
 LDMCCFD SP!,{PC} ;then all ok
 CMP R1,R8 ;see if remembered address already in bottom half
 LDMCSFD SP!,{PC}
 SUBS R0,R4,R8 ;work out how far replaced string is from remembered address
 MOVCC R0,#0 ;if memory inside the replaced string then pretend it's the start
 SUB R8,R1,R0 ;displacement w.r.t. old GS
; CMP R8,R3 ;check if displacement "strange"
; MOVHI R8,R3 ;then reset remembered address
 LDMFD SP!,{PC}
REPLF1 LDRB R0,[R7],#1 ;field number
 MOV R0,R0,LSL #1 ;double it
 ADD R0,R0,#FIELDT
 ADD R0,R0,ARGP ;add address of FIELDT
 LDRB R2,[R0,#1] ;get mmx
 CMP R2,#&80
 BCS REPLF2
 TEQ R2,#0 ;before any multiples
 MOVEQ R2,R4
 BEQ REPLF3
 ADD R2,R2,R2,LSL #1 ;mult by 3 (items per MSTACK entry)
 ADD R2,ARGP,R2,LSL #2 ;mult by 4
 ADD R2,R2,#MSTACK ;add address of MSTACK
 LDR R2,[R2,#8-12] ;get text address end off MSTACK
REPLF3 LDRB R0,[R0]
 LDRB R0,[R2,R0]
 STRB R0,[R3],#1
 B REPL1
REPLF2 BIC R0,R2,#&80 ;remove flag
 ADD R0,R0,R0,LSL #1;*3
 ADD R0,ARGP,R0,LSL #2
 ADD R0,R0,#MSTACK
 LDR R2,[R0,#4-12] ;text Start
 LDR R14,[R0,#8-12] ;text end
 B REPLA1
REPLES LDRB R0,[R7],#1
 STRB R0,[R3],#1
 B REPL1
REPLAM MOV R2,R4 ;& start
 MOV R14,R5 ;& end
REPLA1 CMP R2,R14
 BCS REPL1
 LDRB R0,[R2],#1
 STRB R0,[R3],#1
 CMP R3,R4
 BCC REPLA1
REPLER BL NORMAL
 BL MSG
 = "Not enough memory to replace",0
 LNK Text
